package lyl.lang;

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Properties;

import org.apache.log4j.Logger;


/**
 * 用来加载类，ｃｌａｓｓｐａｔｈ下的资源文件，属性文件等。
 * getExtendResource(StringrelativePath)方法，可以使用../符号来加载classpath外部的资源。
 */
public class ClassLoaderUtil{
    private static Logger log = Logger.getLogger(ClassLoaderUtil.class);

    /**
     * 加载Java类。 使用全限定类名
     * 
     * @paramclassName
     * @return
     */
    public static Class loadClass(String className) {
        try {
            return getClassLoader().loadClass(className);
        }
        catch (ClassNotFoundException e) {
            throw new RuntimeException("class not found '" + className + "'", e);
        }
    }

    /**
     * 得到类加载器
     * 
     * @return
     */
    public static ClassLoader getClassLoader() {
        return ClassLoaderUtil.class.getClassLoader();
    }

    /**
     * 提供相对于classpath的资源路径，返回文件的输入流
     * 
     * @paramrelativePath必须传递资源的相对路径。是相对于classpath的路径。如果需要查找classpath外部的资源，需要使用 ../来查找
     * @return 文件输入流
     * @throwsIOException
     * @throwsMalformedURLException
     */
    public static InputStream getStream(String relativePath) throws  Exception {
        if (relativePath.indexOf("../") == -1) {
            return getClassLoader().getResourceAsStream(relativePath);
        }
        else {
            return ClassLoaderUtil.getStreamByExtendResource(relativePath);
        }
    }

    /**
     * @paramurl
     * @return
     * @throwsIOException
     */
    public static InputStream getStream(URL url) throws IOException {
        if (url != null) {
            return url.openStream();
        }
        else {
            return null;
        }
    }

    /**
     * @paramrelativePath必须传递资源的相对路径。是相对于classpath的路径。如果需要查找classpath外部的资源，需要使用 ../来查找
     * @return
     * @throwsMalformedURLException
     * @throwsIOException
     */
    public static InputStream getStreamByExtendResource(String relativePath) throws MalformedURLException, Exception {
        try {
            return ClassLoaderUtil.getStream(getExtendResource(relativePath));
        }
        catch (IOException e) {
            // 向上级目录查找,by lyl
            // return getStreamByExtendResource("../"+relativePath);
            throw e;
        }
    }

    /**
     * 提供相对于classpath的资源路径，返回属性对象，它是一个散列表
     * 
     * @paramresource
     * @return
     */
    public static Properties getProperties(String resource) {
        Properties properties = new Properties();
        try {
            properties.load(getStream(resource));
        }
        catch (Exception e) {
            throw new RuntimeException("couldn't load properties file '" + resource + "'", e);
        }
        return properties;
    }

    /**
     * 得到本Class所在的ClassLoader的Classpat的绝对路径。 URL形式的
     * 
     * @return
     */
    public static String getAbsolutePathOfClassLoaderClassPath() {
        // log.info(" ClassLoader =
        // "+ClassLoaderUtil.getClassLoader().getClass().getName());
        // log.info("AbsolutePathOfClassLoaderClassPath =
        // "+ClassLoaderUtil.getClassLoader().getResource(
        // "").toString());
        return ClassLoaderUtil.getClassLoader().getResource("").toString();
    }

    /**
     * @throws Exception
     * @throws IOException
     * @paramrelativePath 必须传递资源的相对路径。是相对于classpath的路径。如果需要查找classpath外部的资源，需要使
     *                    用../来查找
     * @return资源的绝对URL
     * @throwsMalformedURLException
     */
    public static URL getExtendResource(String relativePath) throws Exception {
        String path = relativePath;
        // System.out.println("传入的相对路径：" + relativePath);
        // System.out.println(Integer.valueOf(relativePath.indexOf("../")))
        // ;
        if (relativePath.indexOf("../") == -1) {
            return getResource(relativePath);
        }
        String classPathAbsolutePath = ClassLoaderUtil.getAbsolutePathOfClassLoaderClassPath();
        if (relativePath.substring(0, 1).equals("/")) {
            relativePath = relativePath.substring(1);
        }
        // System.out.println(Integer.valueOf(relativePath
        // .lastIndexOf("../")));
        String wildcardString = relativePath.substring(0, relativePath.lastIndexOf("../") + 3);
        relativePath = relativePath.substring(relativePath.lastIndexOf("../") + 3);
        int containSum = ClassLoaderUtil.containSum(wildcardString, "../");
        if (containSum > 10)
            throw new Exception("配置文件没有找到!" + relativePath);// by lyl,不严密
        classPathAbsolutePath = ClassLoaderUtil.cutLastString(classPathAbsolutePath, "/",
                containSum);
        String resourceAbsolutePath = classPathAbsolutePath + relativePath;
        // log.info("resourceAbsolutePath=" + resourceAbsolutePath);
        URL resourceAbsoluteURL = null;
        try {
            resourceAbsoluteURL = new URL(resourceAbsolutePath);
            resourceAbsoluteURL.openStream();
        }
        catch (MalformedURLException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
            throw e1;
        }
        catch (IOException e) {
            // 向上级目录查找,by lyl
            return getExtendResource("../" + path);
        }
        return resourceAbsoluteURL;
    }

    /**
     * @paramsource
     * @paramdest
     * @return
     */
    private static int containSum(String source, String dest) {
        int containSum = 0;
        int destLength = dest.length();
        while (source.indexOf(dest) != -1) {
            containSum = containSum + 1;
            source = source.substring(destLength);
        }
        return containSum;
    }

    /**
     * @paramsource
     * @paramdest
     * @paramnum
     * @return
     */
    private static String cutLastString(String source, String dest, int num) {
        // String cutSource=null;
        for (int i = 0; i < num; i++) {
            source = source.substring(0, source.lastIndexOf(dest, source.length() - 2) + 1);
        }
        return source;
    }

    /**
     * @paramresource
     * @return
     */
    public static URL getResource(String resource) {
        // System.out.println("传入的相对于classpath的路径：" + resource);
        return ClassLoaderUtil.getClassLoader().getResource(resource);
    }

    /**
     * @throws IOException
     * @paramargs
     * @throwsMalformedURLException
     */
    public static void main(String[] args) throws Exception {
        // ClassLoaderUtil.getExtendResource("../spring/dao.xml");
        // ClassLoaderUtil.getExtendResource("../../../src/log4j.properties");
        ClassLoaderUtil.getExtendResource("jndi.properties");
        // log.info(ClassLoaderUtil.getClassLoader().getResource(
        // "jndi.properties").toString());
    }
}